package com.jufa_3.common;

import com.alibaba.fastjson.JSONObject;
import com.jufa_3.config.WeiXinConfig;
import com.jufa_3.dto.OrderReturnInfo;
import com.jufa_3.dto.PayInfo;
import com.jufa_3.dto.QueryReturnInfo;
import com.jufa_3.dto.SignInfo;
import com.thoughtworks.xstream.XStream;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


public class WeiChat {

    /**
     * 获取openid
     *
     * @param loginCode
     * @return
     */
    public static JSONObject getUserOpenId(String loginCode) {
        StringBuffer params = new StringBuffer();
        // 小程序appId
        params.append("appid=" + WeiXinConfig.getAppID());
        // 小程序secret
        params.append("&secret=" + WeiXinConfig.getSecret());
        // 小程序端发来的临时登入凭证code
        params.append("&js_code=" + loginCode);
        // 默认参数
        params.append("&grant_type=authorization_code");
        // 发送post请求调用微信接口获取用户唯一标识openid
        JSONObject openIdJs = RequestTool.sendPostgetOpenId(WeiXinConfig.getOpen_id_url(), params.toString());
        return openIdJs;
    }

    /**
     * 根据传来的手机的码信息获取手机信息
     *
     * @param code
     * @return
     */
    public static String getUserPhoneNum(String code) {
        String grant_type = "client_credential";  // 授权（必填）
        // 向微信服务器 使用登录凭证 code 获取 session_key 和 openid
        String params = "appid=" + WeiXinConfig.getAppID() + "&secret=" + WeiXinConfig.getSecret() + "&grant_type=" + grant_type; // 请求参数

        String tokenJs = (String) RequestTool.sendGet(WeiXinConfig.getToken_url(), params); // 发送请求
        String access_token = JSONObject.parseObject(tokenJs).getString("access_token");   // 解析相应内容（转换成json对象）
        //使用获取到的token和接受到的code像微信获取手机号
        String url = WeiXinConfig.getPhone_url() + "?access_token=" + access_token;
        JSONObject paramsJs = new JSONObject();
        paramsJs.put("code", code);
        String phoneJs = (String) RequestTool.sendPost(url, paramsJs.toJSONString());
        JSONObject phone_info = JSONObject.parseObject(phoneJs);
        return phone_info.getJSONObject("phone_info").getString("phoneNumber");
    }

    /**
     * 发起支付
     *
     * @param payInfo
     * @return
     */
    public static Map<String, String> payment(PayInfo payInfo) throws DocumentException {
        // 生成签名
        String result = null;
        try {
            payInfo.setSign(Signature.getSign(payInfo));
            result = RequestTool.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", payInfo);
        } catch (IllegalAccessException | IOException e) {
            e.printStackTrace();
        }
        //将给定的String文本解析为XML文档并返回新创建的document
        org.dom4j.Document document = DocumentHelper.parseText(result);
        //获取根节点,在例子中就是responsedata节点
        Element rootElement = document.getRootElement();
        //获取根节点下的某个元素
        OrderReturnInfo returnInfo = new OrderReturnInfo(
                (String) rootElement.element("return_code").getData(),
                (String) rootElement.element("return_msg").getData(),
                (String) rootElement.element("result_code").getData(),
                (String) rootElement.element("mch_id").getData(),
                (String) rootElement.element("appid").getData(),
                (String) rootElement.element("nonce_str").getData(),
                (String) rootElement.element("sign").getData(),
                (String) rootElement.element("prepay_id").getData(),
                (String) rootElement.element("trade_type").getData()
        );

//        XStream xStream = new XStream();
//        xStream.alias("xml", OrderReturnInfo.class);
//        OrderReturnInfo returnInfo = (OrderReturnInfo) xStream.fromXML(result);
        // 二次签名
        if ("SUCCESS".equals(returnInfo.getReturn_code()) && returnInfo.getReturn_code().equals(returnInfo.getResult_code())) {
            SignInfo signInfo = new SignInfo();
            signInfo.setAppId(payInfo.getAppid());
            long time = System.currentTimeMillis() / 1000;
            signInfo.setTimeStamp(String.valueOf(time));
            signInfo.setNonceStr(payInfo.getNonce_str());
            signInfo.setRepay_id("prepay_id=" + returnInfo.getPrepay_id());
            signInfo.setSignType("MD5");
            // 生成签名
            String paySign = null;
            try {
                paySign = Signature.getSign(signInfo);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            Map<String, String> payReturnInfo = new HashMap<>();
            payReturnInfo.put("timeStamp", signInfo.getTimeStamp());
            payReturnInfo.put("nonceStr", signInfo.getNonceStr());
            payReturnInfo.put("package", signInfo.getRepay_id());
            payReturnInfo.put("signType", signInfo.getSignType());
            payReturnInfo.put("out_trade_no", payInfo.getOut_trade_no());
            payReturnInfo.put("paySign", paySign);
            return payReturnInfo;
        }
        return null;
    }

    /**
     * 提取支付回调参数
     *
     * @param request
     * @return
     * @throws Exception
     */
    public static Map<String, String> notifyDecode(HttpServletRequest request) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        String notityXml = sb.toString();  // sb为微信返回的xml
        return PayUtil.doXMLParse(notityXml);
    }

    /**
     * 验证签名
     *
     * @param map
     * @return
     */
    public static boolean verifySign(Map<String, String> map) {
        Map<String, String> validParams = PayUtil.paraFilter(map);  // 回调验签时需要去除sign和空值参数
        String validStr = PayUtil.createLinkString(validParams);    // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String sign = PayUtil.sign(validStr, WeiXinConfig.getPublic_Key(), "utf-8").toUpperCase();//拼装生成服务器端验证的签名
        return sign.equals(map.get("sign"));
    }

    /**
     * 查询支付结果
     *
     * @param OutTradeNo
     * @return
     */
    public static QueryReturnInfo orderQuery(String OutTradeNo) {
        Map<String, Object> map = new HashMap<>();
        try {
            PayInfo order = new PayInfo();
            order.setOut_trade_no(OutTradeNo);
            String sign = Signature.getSign(order);
            order.setSign(sign);
            String result = RequestTool.sendPost(WeiXinConfig.getQuery_url(), order);
            XStream xStream = new XStream();
            xStream.alias("xml", QueryReturnInfo.class);
            QueryReturnInfo returnInfo = (QueryReturnInfo) xStream.fromXML(result);
            return returnInfo;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 随机生成验证码
     *
     * @param length 长度为4位或者6位
     * @return
     */
    public static Integer generateValidateCode(int length) {
        Integer code = null;
        if (length == 4) {
            code = new Random().nextInt(9999);//生成随机数，最大为9999
            if (code < 1000) {
                code = code + 1000;//保证随机数为4位数字
            }
        } else if (length == 6) {
            code = new Random().nextInt(999999);//生成随机数，最大为999999
            if (code < 100000) {
                code = code + 100000;//保证随机数为6位数字
            }
        } else {
            throw new RuntimeException("只能生成4位或6位数字验证码");
        }
        return code;
    }

    /**
     * 生成此用户的令牌
     *
     * @return
     */
    public static String getToken(String openId, String role) {
        Map map = new HashMap<String,String>();
        map.put("role",role);
        String token = Jwts.builder()
                .setIssuedAt(new Date())
                .setId(openId)
                .setClaims(map)
//                .setExpiration(new Date(System.currentTimeMillis() + 60*1000 ))
                .setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000 * 7))
                .signWith(SignatureAlgorithm.HS256, "jufa888")
                .compact();
        return token;
    }

}
